#include <check.h>
#include "test_lexer.h"

#include <signal.h>
#include <assert.h>
#include "lexer.h"

#define TEST_FILE "lexer/test"

/* Compartidas por los tests... */
static Lexer *l = NULL;
static FILE *input = NULL;

static void setup (void) {
	l = NULL;
	input = NULL;
}

static void teardown (void) {
	if (l != NULL)
		lexer_destroy (l);
	if (input != NULL)
		fclose (input);
}

static void make_test_file (const char *content) {
	FILE *test_file = fopen (TEST_FILE, "w");
	int error = 0;
	assert (test_file != NULL);
	error = fputs (content, test_file);
	assert (error != EOF);
	fclose (test_file);
	input = fopen (TEST_FILE, "r");
	assert (input);
	l = lexer_new (input);
	assert (l);
}

/* Testeo de precondiciones */
START_TEST (test_new_null)
{
	l = lexer_new (NULL);
	lexer_destroy(l); l = NULL;
}
END_TEST

START_TEST (test_destroy_null)
{
	lexer_destroy(NULL);
}
END_TEST

START_TEST (test_is_started_null)
{
	lexer_is_started(NULL);
}
END_TEST

START_TEST (test_is_off_null)
{
	lexer_is_off(NULL);
}
END_TEST

START_TEST (test_item_null)
{
	lexer_item (NULL);
}
END_TEST

START_TEST (test_item_on_is_off)
{
	make_test_file ("");
	lexer_next (l, ALPHA);
	/* Aquí debería valer lexer_is_off (l) */
	assert (lexer_is_off(l));
	bdestroy (lexer_item (l));
}
END_TEST

START_TEST (test_item_before_start)
{
	make_test_file ("");
	/* Aquí debería valer !lexer_is_started (l) */
	assert (!lexer_is_started(l));
	bdestroy (lexer_item (l));
}
END_TEST

START_TEST (test_next_null)
{
	lexer_next (NULL, ALPHA);
}
END_TEST

START_TEST (test_next_null_charset)
{
	make_test_file ("abc");
	lexer_next (l, NULL);
}
END_TEST

START_TEST (test_next_to_null)
{
	lexer_next_to (NULL, ALPHA);
}
END_TEST

START_TEST (test_next_to_null_charset)
{
	make_test_file ("abc");
	lexer_next_to (l, NULL);
}
END_TEST

START_TEST (test_next_char_null)
{
	lexer_next_char (NULL, ALPHA);
}
END_TEST

START_TEST (test_next_char_null_charset)
{
	make_test_file ("abc");
	lexer_next_char (l, NULL);
}
END_TEST

START_TEST (test_skip_null)
{
	lexer_skip (NULL, ALPHA);
}
END_TEST

START_TEST (test_skip_null_charset)
{
	make_test_file ("abc");
	lexer_skip (l, NULL);
}
END_TEST

START_TEST (test_skip_to_null)
{
	lexer_skip_to (NULL, ALPHA);
}
END_TEST

START_TEST (test_skip_to_null_charset)
{
	make_test_file ("abc");
	lexer_skip_to (l, NULL);
}
END_TEST

/* Testeo de funcionalidad */

/* Constructores y destructores */

START_TEST (test_new)
{
	int c1 = '\0', c2 = '\0', c3 = '\0', c4 = '\0';

	make_test_file ("test");
	/* Verificamos estado inicial */
	fail_unless (!lexer_is_off (l));
	fail_unless (!lexer_is_started (l));
	/* Y que sólo haya consumido el primer caracter */
	c1 = fgetc (input);
	c2 = fgetc (input);
	c3 = fgetc (input);
	c4 = fgetc (input);
	fail_unless (c1 == 'e');
	fail_unless (c2 == 's');
	fail_unless (c3 == 't');
	fail_unless (c4 == EOF);
}
END_TEST

START_TEST (test_destroy_does_not_close)
{
	int c1 = '\0', c2 = '\0', c3 = '\0', c4 = '\0';

	make_test_file ("test");
	lexer_destroy (l);
	l = NULL;
	/* Verificamos que sólo haya consumido el primer caracter, y que el
	 * archivo de entrada siga abierto
	 */
	c1 = fgetc (input);
	c2 = fgetc (input);
	c3 = fgetc (input);
	c4 = fgetc (input);
	fail_unless (c1 == 'e');
	fail_unless (c2 == 's');
	fail_unless (c3 == 't');
	fail_unless (c4 == EOF);
}
END_TEST

/* lexer_next (y su relación con is_off, is_started, item) */

START_TEST (test_next_reads)
{
	int c1 = '\0', c2 = '\0', c3 = '\0', c4 = '\0';
	make_test_file ("siete ocho nueve");
	
	lexer_next(l, ALPHA);
	/* Verificamos que se consumió la palabra, y que el
	 * archivo de entrada siga abierto
	 */
	c1 = fgetc (input);
	c2 = fgetc (input);
	c3 = fgetc (input);
	c4 = fgetc (input);
	/* El espacio _fue_ consumido por el lexer para detectar que terminó
	 * la palabra, incluso si no forma parte de la palabra
	 */
	fail_unless (c1 == 'o');
	fail_unless (c2 == 'c');
	fail_unless (c3 == 'h');
	fail_unless (c4 == 'o');
}
END_TEST

START_TEST (test_next_sets_started)
{
	make_test_file ("siete ocho nueve");
	
	lexer_next(l, ALPHA);
	fail_unless (lexer_is_started(l));
}
END_TEST

START_TEST (test_item_gets_last_by_next)
{
	bstring word = NULL;
	make_test_file ("siete ocho nueve");
	
	lexer_next(l, ALPHA);
	word = lexer_item (l);
	/* item devuelve lo último que consumió next */
	fail_unless (biseqcstr (word, "siete"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_chains)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_next(l, ALPHA);
	word1 = lexer_item (l);
	fail_unless (biseqcstr(word1, "siete"));
	bdestroy (word1);

	lexer_next(l, DIGIT);
	word2 = lexer_item (l);
	/* No se saltean caracteres al hacer dos lecturas seguidas */
	fail_unless (biseqcstr(word2, "7654321"));
	bdestroy (word2);
}
END_TEST

START_TEST (test_next_stops_on_eof)
{
	bstring word = NULL;
	make_test_file ("siete");
	
	lexer_next(l, ALPHA);
	word = lexer_item (l);
	/* Se consumió todo el input sin problemas */
	fail_unless (biseqcstr(word, "siete"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_sets_is_off)
{
	make_test_file ("siete");
	
	lexer_next(l, ALPHA);
	/* Luego de leer una palabra correctamente, aún al final del archivo, 
	 * no se setea is_off */
	fail_unless (!lexer_is_off(l));

	lexer_next(l, ALPHA);
	/* Cualquier avance cuando ya se consumió todo, setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_next_on_empty_file)
{
	make_test_file ("");
	
	lexer_next(l, ALPHA);
	/* Está vacío, se setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_next_on_nonmatch)
{
	bstring word = NULL;

	make_test_file ("siete");

	lexer_next(l, DIGIT);
	word = lexer_item(l);
	/* No se leyó nada: */
	fail_unless (biseqcstr(word, ""));
	
	/* Verificamos que la lectura siga donde toca: */
	lexer_next (l, ALPHA);
	word = lexer_item (l);
	bdestroy (word);
	fail_unless (biseqcstr(word, "siete"));
}
END_TEST

START_TEST (test_next_preserves_last_item)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_next(l, ALPHA);
	word1 = lexer_item (l);
	lexer_next(l, DIGIT);
	word2 = lexer_item (l);

	/* Las dos lecturas son objetos independientes (i.e., el segundo `next' no
	 * "pisó" el objeto devuelto por el primer `item'.
	 */
	fail_unless (word1 != word2); /* Distintos punteros */
	fail_unless (biseqcstr(word1, "siete"));
	fail_unless (biseqcstr(word2, "7654321"));
	bdestroy (word1);
	bdestroy (word2);
}
END_TEST

/* Una propiedad de item */

START_TEST (test_item_idempotent)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("siete ocho nueve");
	
	lexer_next(l, ALPHA);
	word1 = lexer_item (l);
	word2 = lexer_item (l);
	/* Llamar a item muchas veces devuelve siempre la misma cadena
	 * (no dos cadenas iguales, sino el mismo puntero)
	 */
	fail_unless (word1 == word2);
	bdestroy (word1);
}
END_TEST

/* Las mismas propiedades de next, en next_to */

START_TEST (test_next_to_reads)
{
	bstring word = NULL;
	make_test_file ("siete ocho/nueve");
	
	lexer_next_to(l, " ");
	/* Verificamos que se consumió la palabra, y que quedó donde corresponde */
	lexer_next (l, " " ALPHA);
	word = lexer_item(l);
	fail_unless (biseqcstr (word, " ocho"));
}
END_TEST

START_TEST (test_next_to_sets_started)
{
	make_test_file ("siete ocho nueve");
	
	lexer_next_to (l, " ");
	fail_unless (lexer_is_started(l));
}
END_TEST

START_TEST (test_item_gets_last_by_next_to)
{
	bstring word = NULL;
	make_test_file ("siete ocho nueve");
	
	lexer_next_to(l, " ");
	word = lexer_item (l);
	/* item devuelve lo último que consumió next_to */
	fail_unless (biseqcstr (word, "siete"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_to_chains)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_next_to(l, DIGIT);
	word1 = lexer_item (l);
	fail_unless (biseqcstr(word1, "siete"));
	bdestroy (word1);

	lexer_next_to(l, " ");
	word2 = lexer_item (l);
	/* No se saltean caracteres al hacer dos lecturas seguidas */
	fail_unless (biseqcstr(word2, "7654321"));
	bdestroy (word2);
}
END_TEST

START_TEST (test_next_to_stops_on_eof)
{
	bstring word = NULL;
	make_test_file ("siete");
	
	lexer_next_to (l, DIGIT);
	word = lexer_item (l);
	/* Se consumió todo el input sin problemas */
	fail_unless (biseqcstr(word, "siete"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_to_sets_is_off)
{
	make_test_file ("siete");
	
	lexer_next_to(l, DIGIT);
	/* Luego de leer una palabra correctamente, aún al final del archivo, 
	 * no se setea is_off */
	fail_unless (!lexer_is_off(l));

	lexer_next_to(l, ALPHA);
	/* Cualquier avance cuando ya se consumió todo, setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_next_to_on_empty_file)
{
	make_test_file ("");
	
	lexer_next_to(l, ALPHA);
	/* Está vacío, se setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_next_to_on_nonmatch)
{
	bstring word = NULL;

	make_test_file ("siete");

	lexer_next_to(l, ALPHA);
	/* No se leyó nada: */
	fail_unless (biseqcstr(word, ""));
	bdestroy(word);
	/* Verificamos que no se haya consumido nada, y que el
	 * archivo de entrada siga abierto
	 */
	lexer_next (l, ALPHA);
	word = lexer_item (l);
	fail_unless (biseqcstr(word, "siete"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_to_preserves_last_item)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_next_to(l, DIGIT);
	word1 = lexer_item (l);
	lexer_next_to(l, " ");
	word2 = lexer_item (l);

	/* Las dos lecturas son objetos independientes (i.e., el segundo `next' no
	 * "pisó" el objeto devuelto por el primer `item'.
	 */
	fail_unless (word1 != word2); /* Distintos punteros */
	fail_unless (biseqcstr(word1, "siete"));
	fail_unless (biseqcstr(word2, "7654321"));
	bdestroy (word1);
	bdestroy (word2);
}
END_TEST

START_TEST (test_next_to_empty_consumes_all)
{
	bstring word = NULL;
	const char *test_string = "siete7654321 cero   ,.;()\t xxx\n\n";
	make_test_file (test_string);
	
	lexer_next_to(l, "");
	word = lexer_item (l);

	/* Leyó todo por pasar un conjunto vacío de símbolos de detención */
	fail_unless (biseqcstr(word, test_string));
	bdestroy (word);
}
END_TEST

/* lexer_next_char (y su relación con is_off, is_started, item) */

START_TEST (test_next_char_reads)
{
	bstring word = NULL;
	make_test_file ("*+-/");
	
	lexer_next_char(l, "*");
	/* Verificamos que se consumió el caracter, y que el
	 * archivo de entrada siga abierto
	 */
	lexer_next_to (l, "");
	word = lexer_item (l);
	fail_unless (biseqcstr (word, "+-/"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_char_reads_one)
{
	bstring word = NULL;
	make_test_file ("**++");
	
	lexer_next_char(l, "*+");
	word = lexer_item (l);
	/* Se consumió sólo un caracter */
	fail_unless (biseqcstr(word, "*"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_char_sets_started)
{
	make_test_file ("siete ocho nueve");
	
	lexer_next_char(l, ALPHA);
	fail_unless (lexer_is_started(l));
}
END_TEST

START_TEST (test_item_gets_last_by_next_char)
{
	bstring word = NULL;
	make_test_file ("*+-/*");
	
	lexer_next_char (l, "*");
	word = lexer_item (l);
	/* item devuelve lo último que consumió next_char */
	fail_unless (biseqcstr (word, "*"));
	bdestroy (word);
}
END_TEST

START_TEST (test_next_char_chains)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("*+-/");
	
	lexer_next_char(l, "*");
	word1 = lexer_item (l);
	fail_unless (biseqcstr(word1, "*"));
	bdestroy (word1);

	lexer_next_char (l, "+");
	word2 = lexer_item (l);
	/* No se saltean caracteres al hacer dos lecturas seguidas */
	fail_unless (biseqcstr(word2, "+"));
	bdestroy (word2);
}
END_TEST

START_TEST (test_next_char_sets_is_off)
{
	make_test_file ("+");
	
	lexer_next_char(l, "+");
	/* Luego de leer un caracter correctamente, aún al final del archivo, 
	 * no se setea is_off */
	fail_unless (!lexer_is_off(l));

	lexer_next_char(l, "+");
	/* Cualquier avance cuando ya se consumió todo, setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_next_char_on_empty_file)
{
	make_test_file ("");
	
	lexer_next_char(l, "+");
	/* Está vacío, se setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_next_char_on_nonmatch)
{
	bstring word = NULL;

	make_test_file ("+-*");

	lexer_next_char (l, "*");
	/* No se leyó nada: */
	fail_unless (biseqcstr(word, ""));
	bdestroy(word);
	/* Verificamos que no haya consumido, y que el
	 * archivo de entrada siga abierto
	 */
	lexer_next_to (l, "");
	fail_unless (biseqcstr(word, "+-*"));
	word = lexer_item(l);
	bdestroy (word);
}
END_TEST

START_TEST (test_next_char_preserves_last_item)
{
	bstring word1 = NULL, word2 = NULL;
	make_test_file ("+* ");
	
	lexer_next_char (l, "+");
	word1 = lexer_item (l);
	lexer_next_char (l, "*");
	word2 = lexer_item (l);

	/* Las dos lecturas son objetos independientes (i.e., el segundo `next' no
	 * "pisó" el objeto devuelto por el primer `item'.
	 */
	fail_unless (word1 != word2); /* Distintos punteros */
	fail_unless (biseqcstr(word1, "+"));
	fail_unless (biseqcstr(word2, "*"));
	bdestroy (word1);
	bdestroy (word2);
}
END_TEST

/* lexer_skip (y su relación con is_off, is_started, item) */

START_TEST (test_skip_advances)
{
	bstring word = NULL;
	make_test_file ("siete ocho/nueve");
	
	lexer_skip (l, ALPHA);
	/* Verificamos que se consumió la palabra, y que el
	 * archivo de entrada siga abierto
	 */
	lexer_next (l, " " ALPHA);
	word = lexer_item (l);
	fail_unless (biseqcstr (word, " ocho"));
	bdestroy (word);
}
END_TEST

START_TEST (test_skip_sets_started)
{
	make_test_file ("siete ocho nueve");
	
	lexer_skip(l, ALPHA);
	fail_unless (lexer_is_started(l));
}
END_TEST

START_TEST (test_skip_clears_item)
{
	bstring word = NULL;
	make_test_file ("siete ocho nueve");
	
	lexer_skip(l, ALPHA);
	word = lexer_item (l);
	fail_unless (biseqcstr (word, ""));
	bdestroy (word);
}
END_TEST

START_TEST (test_skip_chains)
{
	bstring  word2 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_skip(l, ALPHA);

	lexer_next(l, DIGIT);
	word2 = lexer_item (l);
	/* No se saltean caracteres al hacer dos lecturas seguidas */
	fail_unless (biseqcstr(word2, "7654321"));
	bdestroy (word2);
}
END_TEST

START_TEST (test_skip_stops_on_eof)
{
	make_test_file ("siete");
	
	lexer_skip(l, ALPHA);
	lexer_next_to (l, "");
	/* skip consumió todo el input, luego next_to no tiene input para leer */
	fail_unless (lexer_is_off (l));
}
END_TEST

START_TEST (test_skip_sets_is_off)
{
	make_test_file ("siete");
	
	lexer_skip(l, ALPHA);
	/* Luego de leer una palabra correctamente, aún al final del archivo, 
	 * no se setea is_off */
	fail_unless (!lexer_is_off(l));

	lexer_skip(l, ALPHA);
	/* Cualquier avance cuando ya se consumió todo, setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_skip_on_nonmatch)
{
	bstring word = NULL;

	make_test_file ("siete");

	lexer_skip(l, DIGIT);
	lexer_next(l, ALPHA);
	word = lexer_item (l);
	/* No se leyó nada: */
	fail_unless (biseqcstr(word, "siete"));
	bdestroy (word);
	
}
END_TEST

START_TEST (test_skip_preserves_last_item)
{
	bstring word1 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_next(l, ALPHA);
	word1 = lexer_item (l);
	lexer_skip(l, DIGIT);

	/* Las dos lecturas son objetos independientes (i.e., el segundo `skip' no
	 * "pisó" el objeto devuelto por el primer `item'.
	 */
	fail_unless (biseqcstr(word1, "siete"));
	bdestroy (word1);
}
END_TEST

/* lexer_skip_to (y su relación con is_off, is_started, item) */

START_TEST (test_skip_to_advances)
{
	bstring word = NULL;
	make_test_file ("siete ocho/nueve");
	
	lexer_skip_to (l, " ");
	/* Verificamos que se consumió la palabra, y que el
	 * archivo de entrada siga abierto
	 */
	lexer_next (l, " " ALPHA);
	word = lexer_item (l);
	fail_unless (biseqcstr (word, " ocho"));
	bdestroy (word);
}
END_TEST

START_TEST (test_skip_to_sets_started)
{
	make_test_file ("siete ocho nueve");
	
	lexer_skip_to (l, " ");
	fail_unless (lexer_is_started(l));
}
END_TEST

START_TEST (test_skip_to_clears_item)
{
	bstring word = NULL;
	make_test_file ("siete ocho nueve");
	
	lexer_skip_to (l, " ");
	word = lexer_item (l);
	fail_unless (biseqcstr (word, ""));
	bdestroy (word);
}
END_TEST

START_TEST (test_skip_to_chains)
{
	bstring  word2 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_skip_to(l, DIGIT);

	lexer_next(l, DIGIT);
	word2 = lexer_item (l);
	/* No se saltean caracteres al hacer dos lecturas seguidas */
	fail_unless (biseqcstr(word2, "7654321"));
	bdestroy (word2);
}
END_TEST

START_TEST (test_skip_to_stops_on_eof)
{
	make_test_file ("siete");
	
	lexer_skip_to (l, DIGIT);
	lexer_next_to (l, "");
	/* skip_to consumió todo el input, luego next_to no tiene input para leer */
	fail_unless (lexer_is_off (l));
}
END_TEST

START_TEST (test_skip_to_sets_is_off)
{
	make_test_file ("siete");
	
	lexer_skip_to (l, DIGIT);
	/* Luego de leer una palabra correctamente, aún al final del archivo, 
	 * no se setea is_off */
	fail_unless (!lexer_is_off(l));

	lexer_skip_to (l, ALPHA);
	/* Cualquier avance cuando ya se consumió todo, setea is_off */
	fail_unless (lexer_is_off(l));
}
END_TEST

START_TEST (test_skip_to_on_nonmatch)
{
	bstring word = NULL;

	make_test_file ("siete");

	lexer_skip_to (l, ALPHA);
	/* No se leyó nada: */
	lexer_next(l, ALPHA);
	word = lexer_item (l);
	fail_unless (biseqcstr(word, "siete"));
	bdestroy (word);
	
}
END_TEST

START_TEST (test_skip_to_preserves_last_item)
{
	bstring word1 = NULL;
	make_test_file ("siete7654321 cero");
	
	lexer_next (l, ALPHA);
	word1 = lexer_item (l);
	lexer_skip_to (l, " ");

	/* Las dos lecturas son objetos independientes (i.e., el segundo `skip' no
	 * "pisó" el objeto devuelto por el primer `item'.
	 */
	fail_unless (biseqcstr(word1, "siete"));
	bdestroy (word1);
}
END_TEST

/* Armado de la test suite */

Suite *lexer_suite (void)
{
	Suite *s = suite_create ("lexer");
	TCase *tc_preconditions = tcase_create ("Precondition");
	TCase *tc_functionality = tcase_create ("Functionality");

	/* Precondiciones */
	tcase_add_checked_fixture (tc_preconditions, setup, teardown);
	tcase_add_test_raise_signal (tc_preconditions, test_new_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_destroy_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_is_started_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_is_off_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_item_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_item_on_is_off, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_item_before_start, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_next_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_next_null_charset, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_next_to_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_next_to_null_charset, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_next_char_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_next_char_null_charset, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_skip_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_skip_null_charset, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_skip_to_null, SIGABRT);
	tcase_add_test_raise_signal (tc_preconditions, test_skip_to_null_charset, SIGABRT);
	suite_add_tcase (s, tc_preconditions);

	/* Funcionalidad */
	tcase_add_checked_fixture (tc_functionality, setup, teardown);
	tcase_add_test (tc_functionality, test_new);
	tcase_add_test (tc_functionality, test_destroy_does_not_close);
	/* Funcionalidad relacionada a `lexer_next' */
	tcase_add_test (tc_functionality, test_next_reads);
	tcase_add_test (tc_functionality, test_next_sets_started);
	tcase_add_test (tc_functionality, test_item_gets_last_by_next);
	tcase_add_test (tc_functionality, test_next_chains);
	tcase_add_test (tc_functionality, test_next_stops_on_eof);
	tcase_add_test (tc_functionality, test_next_sets_is_off);
	tcase_add_test (tc_functionality, test_next_on_empty_file);
	tcase_add_test (tc_functionality, test_next_on_nonmatch);
	tcase_add_test (tc_functionality, test_next_preserves_last_item);
	/* Propiedades de `lexer_item' */
	tcase_add_test (tc_functionality, test_item_idempotent);
	/* Funcionalidad relacionada a `lexer_next_to' */
	tcase_add_test (tc_functionality, test_next_to_reads);
	tcase_add_test (tc_functionality, test_next_to_sets_started);
	tcase_add_test (tc_functionality, test_item_gets_last_by_next_to);
	tcase_add_test (tc_functionality, test_next_to_chains);
	tcase_add_test (tc_functionality, test_next_to_stops_on_eof);
	tcase_add_test (tc_functionality, test_next_to_sets_is_off);
	tcase_add_test (tc_functionality, test_next_to_on_empty_file);
	tcase_add_test (tc_functionality, test_next_to_on_nonmatch);
	tcase_add_test (tc_functionality, test_next_to_preserves_last_item);
	tcase_add_test (tc_functionality, test_next_to_empty_consumes_all);
	/* Funcionalidad relacionada a `lexer_next_char' */
	tcase_add_test (tc_functionality, test_next_char_reads);
	tcase_add_test (tc_functionality, test_next_char_reads_one);
	tcase_add_test (tc_functionality, test_next_char_sets_started);
	tcase_add_test (tc_functionality, test_item_gets_last_by_next_char);
	tcase_add_test (tc_functionality, test_next_char_chains);
	tcase_add_test (tc_functionality, test_next_char_sets_is_off);
	tcase_add_test (tc_functionality, test_next_char_on_empty_file);
	tcase_add_test (tc_functionality, test_next_char_on_nonmatch);
	tcase_add_test (tc_functionality, test_next_char_preserves_last_item);
	suite_add_tcase (s, tc_functionality);
	/* Funcionalidad relacionada a `lexer_skip' */
	tcase_add_test (tc_functionality, test_skip_advances);
	tcase_add_test (tc_functionality, test_skip_sets_started);
	tcase_add_test (tc_functionality, test_skip_clears_item);
	tcase_add_test (tc_functionality, test_skip_chains);
	tcase_add_test (tc_functionality, test_skip_stops_on_eof);
	tcase_add_test (tc_functionality, test_skip_sets_is_off);
	tcase_add_test (tc_functionality, test_skip_on_nonmatch);
	tcase_add_test (tc_functionality, test_skip_preserves_last_item);

	/* Funcionalidad relacionada a `lexer_skip_to' */
	tcase_add_test (tc_functionality, test_skip_to_advances);
	tcase_add_test (tc_functionality, test_skip_to_sets_started);
	tcase_add_test (tc_functionality, test_skip_to_clears_item);
	tcase_add_test (tc_functionality, test_skip_to_chains);
	tcase_add_test (tc_functionality, test_skip_to_stops_on_eof);
	tcase_add_test (tc_functionality, test_skip_to_sets_is_off);
	tcase_add_test (tc_functionality, test_skip_to_on_nonmatch);
	tcase_add_test (tc_functionality, test_skip_to_preserves_last_item);

	return s;
}

